﻿using log4net.Core;
using log4net.Kafka.Common;
using log4net.Kafka.Common.Json;
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Web;

namespace log4net.Kafka
{
    public class LogJsonLayout : LayoutSkeleton
    {
        public String system { get; set; }
        public override void ActivateOptions()
        {

        }

        public override void Format(TextWriter writer, LoggingEvent loggingEvent)
        {
            LogModel logModel = ConvertToLogMdoel(loggingEvent);
            var message = JsonMapper.ToJson(logModel);
            writer.Write(message);
        }

        private LogModel ConvertToLogMdoel(LoggingEvent loggingEvent)
        {
            if (loggingEvent == null) return null;

            var logModel = new LogModel
            {
                system = this.system,
                logger = loggingEvent.LoggerName,
                domain = loggingEvent.Domain,
                identity = loggingEvent.Identity,
                thread = loggingEvent.ThreadName,
                user = loggingEvent.UserName,
                timestamp = loggingEvent.TimeStamp.ToUniversalTime().ToString("O"),
                exception = loggingEvent.ExceptionObject == null ? new object() : ExceptionModel.Create(loggingEvent.ExceptionObject),
                message = loggingEvent.RenderedMessage,
                fix = loggingEvent.Fix.ToString(),
                host = Environment.MachineName,
                level = loggingEvent.Level == null ? null : loggingEvent.Level.DisplayName,
            };

            if (loggingEvent.MessageObject != null && loggingEvent.MessageObject.GetType() != typeof(string))
            {
                if (loggingEvent.MessageObject is Exception)
                {
                    logModel.data = ExceptionModel.Create((Exception)loggingEvent.MessageObject);
                }
                else
                {
                    logModel.data = loggingEvent.MessageObject;
                }
            }
            else
            {
                logModel.data = new object();
            }

            if (loggingEvent.LocationInformation != null)
            {
                logModel.@class = loggingEvent.LocationInformation.ClassName;
                logModel.file = loggingEvent.LocationInformation.FileName;
                logModel.line = loggingEvent.LocationInformation.LineNumber;
                logModel.info = loggingEvent.LocationInformation.FullInfo;
                logModel.method = loggingEvent.LocationInformation.MethodName;
            }

            var ctx = System.Web.HttpContext.Current;
            var threadId = Thread.CurrentThread.ManagedThreadId;
            if (ctx != null)
            {
                logModel.http.url = ctx.Request.Url.ToString();
                logModel.http.method = ctx.Request.HttpMethod;

                foreach (var item in ctx.Request.Headers.AllKeys)
                {
                    logModel.http.header.Add(item, ctx.Request.Headers[item]);
                }
                var bytes = ctx.Request.BinaryRead(ctx.Request.TotalBytes);
                logModel.http.body = Encoding.UTF8.GetString(bytes);
            }
            else
            {

            }

            return logModel;
        }
    }
}
